Introduce grid and tree lines in GtkTreeView. (#106406, Martyn Russell).
authorKristian Rietveld <kris@imendio.com>
Mon, 12 Jun 2006 18:17:35 +0000 (18:17 +0000)
committerKristian Rietveld <kristian@src.gnome.org>
Mon, 12 Jun 2006 18:17:35 +0000 (18:17 +0000)
2006-06-12  Kristian Rietveld  <kris@imendio.com>

Introduce grid and tree lines in GtkTreeView. (#106406,
Martyn Russell).

* gtk/gtktreeprivate.h: add new fields to GtkTreePrivate.

* gtk/gtkenums.h: add GtkTreeViewGridLines.

* gtk/gtktreeview.[ch] (gtk_tree_view_set_grid_lines),
(gtk_tree_view_get_grid_lines),
(gtk_tree_view_set_enable_tree_lines),
(gtk_tree_view_get_enable_tree_lines): new API,
(gtk_tree_view_class_init): new properties,
(gtk_tree_view_init), (gtk_tree_view_{get,set}_property),
(gtk_tree_view_realize), (gtk_tree_view_draw_grid_lines),
(gtk_tree_view_bin_expose): implement.

* gtk/gtk.symbols: update.

ChangeLog
ChangeLog.pre-2-10
gtk/gtk.symbols
gtk/gtkenums.h
gtk/gtktreeprivate.h
gtk/gtktreeview.c
gtk/gtktreeview.h

index c773da6f887ad0e21009636ffdd15438823d6b73..fd88d9e39f2cd867b69990af082eb2bb9bf6f04d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2006-06-12  Kristian Rietveld  <kris@imendio.com>
+
+       Introduce grid and tree lines in GtkTreeView. (#106406,
+       Martyn Russell).
+
+       * gtk/gtktreeprivate.h: add new fields to GtkTreePrivate.
+
+       * gtk/gtkenums.h: add GtkTreeViewGridLines.
+
+       * gtk/gtktreeview.[ch] (gtk_tree_view_set_grid_lines),
+       (gtk_tree_view_get_grid_lines),
+       (gtk_tree_view_set_enable_tree_lines),
+       (gtk_tree_view_get_enable_tree_lines): new API,
+       (gtk_tree_view_class_init): new properties,
+       (gtk_tree_view_init), (gtk_tree_view_{get,set}_property),
+       (gtk_tree_view_realize), (gtk_tree_view_draw_grid_lines),
+       (gtk_tree_view_bin_expose): implement.
+
+       * gtk/gtk.symbols: update.
+
 2006-06-12  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkprintunixdialog.c (is_printer_active): Use 
index c773da6f887ad0e21009636ffdd15438823d6b73..fd88d9e39f2cd867b69990af082eb2bb9bf6f04d 100644 (file)
@@ -1,3 +1,23 @@
+2006-06-12  Kristian Rietveld  <kris@imendio.com>
+
+       Introduce grid and tree lines in GtkTreeView. (#106406,
+       Martyn Russell).
+
+       * gtk/gtktreeprivate.h: add new fields to GtkTreePrivate.
+
+       * gtk/gtkenums.h: add GtkTreeViewGridLines.
+
+       * gtk/gtktreeview.[ch] (gtk_tree_view_set_grid_lines),
+       (gtk_tree_view_get_grid_lines),
+       (gtk_tree_view_set_enable_tree_lines),
+       (gtk_tree_view_get_enable_tree_lines): new API,
+       (gtk_tree_view_class_init): new properties,
+       (gtk_tree_view_init), (gtk_tree_view_{get,set}_property),
+       (gtk_tree_view_realize), (gtk_tree_view_draw_grid_lines),
+       (gtk_tree_view_bin_expose): implement.
+
+       * gtk/gtk.symbols: update.
+
 2006-06-12  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkprintunixdialog.c (is_printer_active): Use 
index 0fc7c919222a94e10d30524b31dd4ba7763e1fab..8a6b4038c2676c78a6be90a73ab62df36cc7c411 100644 (file)
@@ -4240,8 +4240,10 @@ gtk_tree_view_get_cursor
 gtk_tree_view_get_dest_row_at_pos
 gtk_tree_view_get_drag_dest_row
 gtk_tree_view_get_enable_search
+gtk_tree_view_get_enable_tree_lines
 gtk_tree_view_get_expander_column
 gtk_tree_view_get_fixed_height_mode
+gtk_tree_view_get_grid_lines
 gtk_tree_view_get_hadjustment
 gtk_tree_view_get_headers_clickable
 gtk_tree_view_get_headers_visible
@@ -4280,8 +4282,10 @@ gtk_tree_view_set_cursor_on_cell
 gtk_tree_view_set_destroy_count_func
 gtk_tree_view_set_drag_dest_row
 gtk_tree_view_set_enable_search
+gtk_tree_view_set_enable_tree_lines
 gtk_tree_view_set_expander_column
 gtk_tree_view_set_fixed_height_mode
+gtk_tree_view_set_grid_lines
 gtk_tree_view_set_hadjustment
 gtk_tree_view_set_headers_clickable
 gtk_tree_view_set_headers_visible
index 89de9fa91c34320dc614d428afc70275b83251ab..85bfd38f8236c49b699971b366880188fe21f3da 100644 (file)
@@ -507,6 +507,13 @@ typedef enum {
   GTK_UNIT_MM
 } GtkUnit;
 
+typedef enum {
+  GTK_TREE_VIEW_GRID_LINES_NONE,
+  GTK_TREE_VIEW_GRID_LINES_HORIZONTAL,
+  GTK_TREE_VIEW_GRID_LINES_VERTICAL,
+  GTK_TREE_VIEW_GRID_LINES_BOTH
+} GtkTreeViewGridLines;
+
 G_END_DECLS
 
 #endif /* __GTK_ENUMS_H__ */
index d50b3afa2685dd952f93e9f8c9040a49c7cb4c17..9e7b591c03d81ae2374de079bdba6cbf63aab424 100644 (file)
@@ -255,6 +255,12 @@ struct _GtkTreeViewPrivate
   GtkDestroyNotify row_separator_destroy;
 
   gint level_indentation;
+
+  GtkTreeViewGridLines grid_lines;
+  GdkGC *grid_line_gc;
+
+  gboolean tree_lines_enabled;
+  GdkGC *tree_line_gc;
 };
 
 #ifdef __GNUC__
index 50854c3b124e7c90e6e35f8f2e192fe851d6ad19..5c832f7b57fbb2007f586ac6124342b5189c5e6d 100644 (file)
@@ -136,7 +136,9 @@ enum {
   PROP_HOVER_EXPAND,
   PROP_SHOW_EXPANDERS,
   PROP_LEVEL_INDENTATION,
-  PROP_RUBBER_BANDING
+  PROP_RUBBER_BANDING,
+  PROP_ENABLE_GRID_LINES,
+  PROP_ENABLE_TREE_LINES
 };
 
 /* object signals */
@@ -709,6 +711,22 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                            FALSE,
                                                            GTK_PARAM_READWRITE));
 
+    g_object_class_install_property (o_class,
+                                     PROP_ENABLE_GRID_LINES,
+                                     g_param_spec_boolean ("enable-grid-lines",
+                                                           P_("Enable Grid Lines"),
+                                                           P_("Whether grid lines should be drawn in the tree view"),
+                                                           FALSE,
+                                                           GTK_PARAM_READWRITE));
+
+    g_object_class_install_property (o_class,
+                                     PROP_ENABLE_TREE_LINES,
+                                     g_param_spec_boolean ("enable-tree-lines",
+                                                           P_("Enable Tree Lines"),
+                                                           P_("Whether tree lines should be drawn in the tree view"),
+                                                           FALSE,
+                                                           GTK_PARAM_READWRITE));
+
   /* Style properties */
 #define _TREE_VIEW_EXPANDER_SIZE 12
 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
@@ -776,6 +794,34 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                                 FALSE,
                                                                 GTK_PARAM_READABLE));
 
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_int ("grid-line-width",
+                                                            P_("Grid line width"),
+                                                            P_("Width, in pixels, of the tree view grid lines"),
+                                                            0, G_MAXINT, 1,
+                                                            GTK_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_int ("tree-line-width",
+                                                            P_("Tree line width"),
+                                                            P_("Width, in pixels, of the tree view lines"),
+                                                            0, G_MAXINT, 1,
+                                                            GTK_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_string ("grid-line-pattern",
+                                                               P_("Grid line pattern"),
+                                                               P_("Dash pattern used to draw the tree view grid lines"),
+                                                               "\1\1",
+                                                               GTK_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_string ("tree-line-pattern",
+                                                               P_("Tree line pattern"),
+                                                               P_("Dash pattern used to draw the tree view lines"),
+                                                               "\1\1",
+                                                               GTK_PARAM_READABLE));
+
   /* Signals */
   widget_class->set_scroll_adjustments_signal =
     g_signal_new (I_("set_scroll_adjustments"),
@@ -1261,6 +1307,9 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   tree_view->priv->level_indentation = 0;
 
   tree_view->priv->rubber_banding_enable = FALSE;
+
+  tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
+  tree_view->priv->tree_lines_enabled = FALSE;
 }
 
 \f
@@ -1331,6 +1380,12 @@ gtk_tree_view_set_property (GObject         *object,
     case PROP_RUBBER_BANDING:
       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
       break;
+    case PROP_ENABLE_GRID_LINES:
+      gtk_tree_view_set_grid_lines (tree_view, g_value_get_boolean (value));
+      break;
+    case PROP_ENABLE_TREE_LINES:
+      gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
+      break;
     default:
       break;
     }
@@ -1396,6 +1451,12 @@ gtk_tree_view_get_property (GObject    *object,
     case PROP_RUBBER_BANDING:
       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
       break;
+    case PROP_ENABLE_GRID_LINES:
+      g_value_set_boolean (value, tree_view->priv->grid_lines);
+      break;
+    case PROP_ENABLE_TREE_LINES:
+      g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1716,6 +1777,10 @@ gtk_tree_view_realize (GtkWidget *widget)
   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
 
+  /* Need to call those here, since they craete GCs */
+  gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
+  gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
+
   install_presize_handler (tree_view); 
 }
 
@@ -3930,6 +3995,40 @@ draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
                     1, 1, w, h);
 }
 
+static void
+gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
+                              GdkEventExpose *event,
+                              gint            n_visible_columns)
+{
+  GList *list = tree_view->priv->columns;
+  gint i = 0;
+  gint current_x = 0;
+
+  if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
+      && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
+    return;
+
+  /* Only draw the lines for visible rows and columns */
+  for (list = tree_view->priv->columns; list; list = list->next, i++)
+    {
+      GtkTreeViewColumn *column = list->data;
+
+      /* We don't want a line for the list column */
+      if (i == n_visible_columns - 1)
+       break;
+
+      if (! column->visible)
+       continue;
+
+      current_x += column->width;
+
+      gdk_draw_line (event->window,
+                    tree_view->priv->grid_line_gc,
+                    current_x - 1, 0,
+                    current_x - 1, tree_view->priv->height);
+    }
+}
+
 /* Warning: Very scary function.
  * Modify at your own risk
  *
@@ -4271,6 +4370,80 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                                  background_area.height);
            }
 
+         if (tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
+             || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH)
+           {
+             if (background_area.y > 0)
+               gdk_draw_line (event->window,
+                              tree_view->priv->grid_line_gc,
+                              background_area.x, background_area.y,
+                              background_area.x + background_area.width,
+                              background_area.y);
+           }
+
+         if (gtk_tree_view_is_expander_column (tree_view, column) &&
+             tree_view->priv->tree_lines_enabled)
+           {
+             if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
+                 && depth > 1)
+               {
+                 gdk_draw_line (event->window,
+                                tree_view->priv->tree_line_gc,
+                                background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                background_area.y + background_area.height / 2,
+                                background_area.x + tree_view->priv->expander_size * (depth - 1.1),
+                                background_area.y + background_area.height / 2);
+               }
+             else if (depth > 1)
+               {
+                 gdk_draw_line (event->window,
+                                tree_view->priv->tree_line_gc,
+                                background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                background_area.y + background_area.height / 2,
+                                background_area.x + tree_view->priv->expander_size * (depth - 0.5),
+                                background_area.y + background_area.height / 2);
+               }
+
+             if (depth > 1)
+               {
+                 gint i;
+                 GtkRBNode *tmp_node;
+                 GtkRBTree *tmp_tree;
+
+                 if (!_gtk_rbtree_next (tree, node))
+                   gdk_draw_line (event->window,
+                                  tree_view->priv->tree_line_gc,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y + background_area.height / 2);
+                 else
+                   gdk_draw_line (event->window,
+                                  tree_view->priv->tree_line_gc,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y + background_area.height);
+
+                 tmp_node = tree->parent_node;
+                 tmp_tree = tree->parent_tree;
+
+                 for (i = depth - 2; i > 0; i--)
+                   {
+                     if (_gtk_rbtree_next (tmp_tree, tmp_node))
+                       gdk_draw_line (event->window,
+                                      tree_view->priv->tree_line_gc,
+                                      background_area.x + tree_view->priv->expander_size * (i - 0.5),
+                                      background_area.y,
+                                      background_area.x + tree_view->priv->expander_size * (i - 0.5),
+                                      background_area.y + background_area.height);
+
+                     tmp_node = tmp_tree->parent_node;
+                     tmp_tree = tmp_tree->parent_tree;
+                   }
+               }
+           }
+
          if (gtk_tree_view_is_expander_column (tree_view, column))
            {
              if (!rtl)
@@ -4495,6 +4668,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
       else
        {
          gboolean done = FALSE;
+
          do
            {
              node = _gtk_rbtree_next (tree, node);
@@ -4531,6 +4705,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
   while (y_offset < event->area.height);
 
 done:
+  gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
 
  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
    {
@@ -7548,6 +7723,9 @@ gtk_tree_view_style_set (GtkWidget *widget,
     {
       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
+
+      gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
+      gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
     }
 
   gtk_widget_style_get (widget,
@@ -14257,5 +14435,152 @@ gtk_tree_view_state_changed (GtkWidget      *widget,
   gtk_widget_queue_draw (widget);
 }
 
+/**
+ * gtk_tree_view_get_grid_lines:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns which grid lines are enabled in @tree_view.
+ *
+ * Return value: a #GtkTreeViewGridLines value indicating which grid lines
+ * are enabled.
+ *
+ * Since: 2.10
+ */
+GtkTreeViewGridLines
+gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+  return tree_view->priv->grid_lines;
+}
+
+/**
+ * gtk_tree_view_set_grid_lines:
+ * @tree_view: a #GtkTreeView
+ * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
+ * enable.
+ *
+ * Sets which grid lines to draw in @tree_view.
+ *
+ * Since: 2.10
+ */
+void
+gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
+                             GtkTreeViewGridLines   grid_lines)
+{
+  gint line_width;
+  guint8 *dash_list;
+  GtkWidget *widget;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  widget = GTK_WIDGET (tree_view);
+
+  if (!GTK_WIDGET_REALIZED (widget))
+    {
+      tree_view->priv->grid_lines = grid_lines;
+      return;
+    }
+
+  gtk_widget_style_get (widget,
+                       "grid-line-width", &line_width,
+                       "grid-line-pattern", (gchar *)&dash_list,
+                       NULL);
+
+  if (tree_view->priv->grid_line_gc)
+    g_object_unref (tree_view->priv->grid_line_gc);
+
+  tree_view->priv->grid_lines = grid_lines;
+  if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE)
+    {
+      tree_view->priv->grid_line_gc = NULL;
+      return;
+    }
+
+  tree_view->priv->grid_line_gc = gdk_gc_new (widget->window);
+  gdk_gc_copy (tree_view->priv->grid_line_gc,
+              widget->style->black_gc);
+
+  gdk_gc_set_line_attributes (tree_view->priv->grid_line_gc, line_width,
+                             GDK_LINE_ON_OFF_DASH,
+                             GDK_CAP_BUTT, GDK_JOIN_MITER);
+  gdk_gc_set_dashes (tree_view->priv->grid_line_gc, 0, dash_list, 2);
+
+  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/**
+ * gtk_tree_view_get_enable_tree_lines:
+ * @tree_view: a #GtkTreeView.
+ *
+ * Returns whether or not tree lines are drawn in @tree_view.
+ *
+ * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
+ * otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+  return tree_view->priv->tree_lines_enabled;
+}
+
+/**
+ * gtk_tree_view_set_enable_tree_lines:
+ * @tree_view: a #GtkTreeView
+ * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
+ *
+ * Sets whether to draw lines interconnecting the expanders in @tree_view.
+ * This does not have any visible effects for lists.
+ *
+ * Since: 2.10
+ */
+void
+gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
+                                    gboolean     enabled)
+{
+  gint line_width;
+  guint8 *dash_list;
+  GtkWidget *widget;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  widget = GTK_WIDGET (tree_view);
+
+  if (!GTK_WIDGET_REALIZED (widget))
+    {
+      tree_view->priv->tree_lines_enabled = enabled;
+      return;
+    }
+
+  gtk_widget_style_get (widget,
+                       "tree-line-width", &line_width,
+                       "tree-line-pattern", (gchar *)&dash_list,
+                       NULL);
+
+  if (tree_view->priv->tree_line_gc)
+    g_object_unref (tree_view->priv->tree_line_gc);
+
+  if (!enabled)
+    {
+      tree_view->priv->tree_line_gc = NULL;
+      return;
+    }
+
+  tree_view->priv->tree_line_gc = gdk_gc_new (widget->window);
+  gdk_gc_copy (tree_view->priv->tree_line_gc,
+              widget->style->black_gc);
+
+  gdk_gc_set_line_attributes (tree_view->priv->tree_line_gc, line_width,
+                             GDK_LINE_ON_OFF_DASH,
+                             GDK_CAP_BUTT, GDK_JOIN_MITER);
+  gdk_gc_set_dashes (tree_view->priv->tree_line_gc, 0, dash_list, 2);
+
+  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
 #define __GTK_TREE_VIEW_C__
 #include "gtkaliasdef.c"
index d78e75ae22c96cf53c1a4a778d4feca0b4e45755..26948aa09c18fb04e1f552ce1bfbd05be0a5a354 100644 (file)
@@ -352,6 +352,12 @@ void                        gtk_tree_view_set_row_separator_func (GtkTreeView
                                                                  gpointer                    data,
                                                                  GtkDestroyNotify            destroy);
 
+GtkTreeViewGridLines        gtk_tree_view_get_grid_lines         (GtkTreeView                *tree_view);
+void                        gtk_tree_view_set_grid_lines         (GtkTreeView                *tree_view,
+                                                                 GtkTreeViewGridLines        grid_lines);
+gboolean                    gtk_tree_view_get_enable_tree_lines  (GtkTreeView                *tree_view);
+void                        gtk_tree_view_set_enable_tree_lines  (GtkTreeView                *tree_view,
+                                                                 gboolean                    enabled);
 
 G_END_DECLS